﻿using NAudio.CoreAudioApi;
using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.Linq;


namespace Armon.Lib.Media.Speech
{
    public class SpeechRecorder
    {
        public event EventHandler<StoppedEventArgs>? RecordingStopped;
        private WaveIn? source;
        private WaveFileWriter? writer;

        private readonly string fileName;
        public SpeechRecorder(string fileName)
        {
            this.fileName = fileName;
        }

        private void SetVolume(int volume)
        {
            var devices = FindDevices();
            foreach (var device in devices)
            {
                device.AudioEndpointVolume.MasterVolumeLevelScalar = volume / 100.0f;
            }
        }

        public void Start()
        {
            this.SetVolume(100);

            this.source = new WaveIn
            {
                WaveFormat = new WaveFormat(16000, 16, 1)
            };
            this.source.DataAvailable += OnDataAvailable;
            this.source.RecordingStopped += OnRecordingStopped;
            this.writer = new WaveFileWriter(fileName, source.WaveFormat);
            this.source.StartRecording();
        }

        public void Stop()
        {
            this.source?.StopRecording();
        }

        private void OnDataAvailable(object? sender, WaveInEventArgs e)
        {
            if (writer != null)
            {
                writer.Write(e.Buffer, 0, e.BytesRecorded);
                writer.Flush();
            }
        }

        private void OnRecordingStopped(object? sender, StoppedEventArgs e)
        {
            if (source != null)
            {
                this.source.Dispose();
            }

            if (writer != null)
            {
                this.writer.Close();
                this.writer.Dispose();
            }

            this.RecordingStopped?.Invoke(sender, e);
        }

        public static IEnumerable<MMDevice> FindDevices()
        {
            return new MMDeviceEnumerator()
                .EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.Active);
        }

        public static bool Existed()
        {
            var devices = FindDevices();
            return devices.Any();
        }
    }
}
